package com.letu.core.utils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapFlatUtil {

    private static final String SEPARATOR = ".";


    public static void main(String[] args) {
//        JSONObject jsonObject = new JSONObject();
//        JSONObject jsonObject2 = new JSONObject();
//        jsonObject2.put("aa","11");
//        jsonObject2.put("bb","22");
//        jsonObject.put("name",jsonObject2);
//        jsonObject.put("name2","2222");
//        Map<String, Object> map =   beanToFlatMap(jsonObject);
//        System.out.println(map);

        Map<String, Object> map1 = new HashMap<>();
        map1.put("aa.bb.ccc","2332");
        map1.put("aa.bb.ddd.eeee","2332");
        map1.put("aa.bb.ddd.ffff","2332");
        map1.put("aa.cc","2332");
        JSONObject jsonObject1 = (JSONObject) mapToFlatBean(map1,JSONObject.class);
        System.out.println(jsonObject1);
    }
    /**
     * bean 转 扁平化map
     *
     * @param obj
     * @return
     */
    public static Map<String, Object> beanToFlatMap(Object obj) {
//        Map map = JSONObject.parseObject(JSONObject.toJSONString(obj, SerializerFeature.WriteNullStringAsEmpty), Map.class);
        Map<String,Object> map=new HashMap<String, Object>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            try {
                map.put(field.getName(), field.get(obj));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        Map<String, Object> result = flat(map, null);
        return result;
    }

    /**
     * 扁平化map 转 bean
     *
     * @param map
     * @return
     */
    public static Object mapToFlatBean(Map<String, Object> map, Class c) {
        //解析
        Map<String, Object> unflatMap = unflat(map);
        Object obj = JSONObject.parseObject(JSONObject.toJSONString(unflatMap), c);
        return obj;
    }

    /**
     * 深度嵌套map对象转大map（扁平化）
     *
     * @param source     源map
     * @param parentNode 父节点扁平化之后的名字
     * @return map
     */
    private static Map<String, Object> flat(Map<String, Object> source, String parentNode) {
        Map<String, Object> flat = new HashMap<>();
        Set<Map.Entry<String, Object>> set = source.entrySet();
        String prefix = StringUtils.isNotBlank(parentNode) ? parentNode + SEPARATOR : "";
        set.forEach(entity -> {
            Object value = entity.getValue();
            String key = entity.getKey();
            String newKey = prefix + key;
            if (value instanceof Map) {
                flat.putAll(flat((Map) value, newKey));
            } else {
                flat.put(newKey, value);
            }
        });
        return flat;
    }


    /**
     * 深度嵌套map对象转大map（扁平化）
     *
     * @param source 源map
     * @return map
     */
    private static Map<String, Object> unflat(Map<String, Object> source) {
        Map<String, Object> map = new HashMap<>();
        Set<Map.Entry<String, Object>> set = source.entrySet();
        set.forEach(entity -> {
            Object value = entity.getValue();
            String key = entity.getKey();
            assembleMap(map, null, key, value);
        });
        return map;
    }

    private static void assembleMap(Map<String, Object> map, String parentKey, String key, Object value) {
        if (key.indexOf(SEPARATOR) > -1) {
            //有层级
            parentKey = key.substring(0, key.indexOf(SEPARATOR));
            key = key.substring(key.indexOf(SEPARATOR) + 1);
            assembleMap(map, parentKey, key, value);
        } else {
            if (StringUtils.isNotBlank(parentKey)) {
                Map childMap = (Map) map.get(parentKey);
                if (childMap == null) {
                    childMap = new HashMap();
                }
                childMap.put(key, value);
                map.put(parentKey, childMap);
            } else {
                Object childMap = map.get(key);
                if (childMap instanceof Map) {
                    Map map2 = (Map) childMap;
                    map2.put(key, value);
                } else {
                    map.put(key, value);
                }
            }

        }
    }
}
